from flask import (
    Flask,  #
    redirect,  # 跳到另外一个路由
    request  # 用户发的请求
)

TODOs = []  # 存储所有待办事项的全局列表
app = Flask(__name__)  # 创建 Flask 应用实例

# 用户认证模块
def validate(username, password):
    """验证用户登录信息"""
    if username == "admin" and password == "123456":  # 用户名和密码正确返回 True
        return True
    else:
        return False   # 否则返回 False

# 登录路由
@app.route("/login", methods=["GET", "POST"])
def login():
    """处理登录请求"""
    if request.method == "GET":  # GET 请求返回登录页面
        return renderLoginPage()  # 显示登录表单
    if request.method == "POST":
        # 从表单中获取用户名和密码
        username = request.form.get("username")   # 获取表单用户名
        password = request.form.get("password")   # 获取表单密码
        if validate(username, password):
            # 预计跳转到 /home
            # 验证成功，重定向到主页并设置用户 cookie
            resp = redirect("/home")   #验证成功跳转主页面
            # 设置 response，给用户发放一天的通行证
            resp.set_cookie("username", username, max_age=3600 * 24)    # cookie 有效期一天
            return resp
        else:
            # 如果用户认证信息对不上，需要给出错误提示
            return renderLoginPage()  # 此时enhanced_renderLoginPage会自动添加错误信息

# 登出路由
@app.route("/logout", methods=["POST"])
def logout():
    """处理注销请求"""
    resp = redirect("/login") # 重定向到登录页面
    resp.delete_cookie("username")  # 删除用户 cookie
    return resp

# 主页路由
@app.route("/")
def root():
    """根路径重定向到主页"""
    return redirect("/home") # 根路径重定向到主页


@app.route("/home", methods=["GET", "POST"])
def home():
    """主页路由，处理待办事项的显示和添加"""
    username = request.cookies.get("username")  # 从cookie获取用户名

    print("current login user:", username)

    if username:   # 用户已登录
        # 如果已经给你发了通行证
        if request.method == "GET":
            return renderHomePage()   # GET 请求显示主页

        if request.method == "POST":
            # POST 请求添加新的待办事项
            todo = request.form.get("todo")    # 获取表单输入的待办事项
            TODOs.append(todo)     # 添加到全局列表
            return renderHomePage()
    else:
        # 如果没有发通行证
        # 用户未登录，重定向到登录页面
        return redirect("/login")    # 未认证跳转登录


def _original_renderLoginPage():
    """原始的登录页面渲染函数"""
    pieces = [
        '<form method="POST" action="/login">',
        '  <div><input name="username" placeholder="username" required /></div>',
        '  <div><input name="password" type="password" placeholder="password" required /></div>',
        '  <div><button type="submit">login</button></div>',
        '</form>'
    ]
    return "\n".join(pieces)  # 返回 HTML 表单字符串


def _original_renderHomePage():
    """原始的主页渲染函数"""
    # ul
    #   - li 1
    #   - li 2
    # form
    #   - input
    pieces = [   # 构建主页HTML
        '<form method="POST" action="/logout">',    # 登出按钮
        '  <button>logout</button>',
        '</form>',
        # 显示待办事项列表
        "<ul>%s</ul>" % ("\n".join(("<li>%s</li>" % todo) for todo in TODOs)),   # 待办列表
        '<form method="POST" action="/home">',  # 待办输入框
        '  <input name="todo" required placeholder="input todo" />',
        '  <button>add</button>',
        '</form>'
    ]

    return "\n".join(pieces)  # 返回完整的主页 HTML


# =============== 以下是新增的安全增强模块 ===============
from markupsafe import escape     # 用于转义 HTML 特殊字符，防止 XSS 攻击
from werkzeug.security import generate_password_hash, check_password_hash   # 密码哈希处理
import os


# 安全中间件 - 处理XSS和密码安全
@app.before_request   # 在每个请求前执行
def security_middleware():
    """请求预处理中间件，防止 XSS 攻击"""
    # 对POST请求中的用户输入进行转义
    if request.method == "POST":
        for key in request.form:
            # 创建原始数据的副本，避免修改原始请求对象
            request._form = request.form.copy()
            request._form[key] = escape(request.form[key])  # 转义用户输入防XSS

    # 对所有用户显示的内容进行XSS防护
    global TODOs
    TODOs = [escape(todo) for todo in TODOs]  # 转义现有待办


# 密码安全增强
def enhanced_validate(username, password):
    """增强的用户验证函数，使用密码哈希"""
    # 实际应用中应使用数据库存储
    hashed_password = generate_password_hash("123456")
    if username == "admin" and check_password_hash(hashed_password, password):
        return True  # 验证哈希而非明文
    return False


# 覆盖原始验证函数，使用增强版本
validate = enhanced_validate

# =============== 以下是新增的功能扩展模块 ===============
# 用户隔离的待办事项存储
USER_TODOS = {} # 存储每个用户的待办事项


@app.after_request
def user_specific_todos(response):
    """实现用户隔离的待办事项"""
    username = request.cookies.get("username")
    if username:
        if username not in USER_TODOS:
            USER_TODOS[username] = []  # 为新用户创建待办事项列表

        # 将全局TODOs同步到用户特定列表
        USER_TODOS[username] = [todo for todo in USER_TODOS[username]
                                if todo not in TODOs] + TODOs

        # 清空全局列表，使用用户特定列表
        TODOs.clear()
        TODOs.extend(USER_TODOS[username])
    return response


# 待办事项删除功能
@app.route("/delete", methods=["POST"])
def delete_todo():
    """删除待办事项"""
    username = request.cookies.get("username")
    if username:
        try:
            index = int(request.form.get("index"))
            if 0 <= index < len(TODOs):
                deleted = TODOs.pop(index) # 从列表中删除指定索引的待办事项
                # 也从用户特定列表中删除
                if username in USER_TODOS:
                    if deleted in USER_TODOS[username]:
                        USER_TODOS[username].remove(deleted)
                return redirect("/home")
        except (ValueError, TypeError):
            pass
    return redirect("/login")


# 增强的主页渲染函数
def enhanced_renderHomePage():
    """增强的主页渲染，添加删除功能"""
    # 调用原始的主页渲染函数（而非被覆盖后的自己）
    base_content = _original_renderHomePage()

    # 在列表项中添加删除按钮
    todo_list_start = base_content.find("<ul>") + 4
    todo_list_end = base_content.find("</ul>")
    todo_list = base_content[todo_list_start:todo_list_end]

    # 为每个待办事项添加删除按钮
    enhanced_todos = []
    for i, item in enumerate(todo_list.split("</li>")):
        if item.strip():
            enhanced_item = item.replace("<li>", f'<li id="todo-{i}">')
            enhanced_item += f'''<form method="POST" action="/delete" style="display:inline;">
                <input type="hidden" name="index" value="{i}">
                <button type="submit" style="margin-left:10px;color:red;">×</button>
            </form>'''
            enhanced_todos.append(enhanced_item + "</li>")

    # 重构内容，替换原始列表
    new_todo_list = "<ul>" + "\n".join(enhanced_todos) + "</ul>"
    return base_content.replace(todo_list, new_todo_list.split("<ul>")[1].split("</ul>")[0])

# 覆盖原始渲染函数
renderHomePage = enhanced_renderHomePage


# 增强的登录页面渲染
def enhanced_renderLoginPage():
    """添加登录错误提示"""
    # 调用原始的登录页面渲染函数（而非被覆盖后的自己）
    base_content = _original_renderLoginPage()
    error_message = ""

    # 如果是登录失败后的POST请求
    if request.method == "POST" and request.path == "/login":
        error_message = '<div style="color:red;margin-bottom:15px;">用户名或密码错误</div>'

    # 在表单前插入错误消息
    form_start = base_content.find("<form")
    return base_content[:form_start] + error_message + base_content[form_start:]


# 覆盖原始登录渲染函数
renderLoginPage = enhanced_renderLoginPage

# 避免重复提交的中间件
from flask import g


@app.before_request
def prg_pattern_support():
    """支持PRG(Post-Redirect-Get)模式避免重复提交"""
    if request.method == "POST" and request.path == "/home":
        g.todo_content = request.form.get("todo", "")


@app.after_request
def apply_prg_pattern(response):
    """应用PRG模式"""
    if request.method == "POST" and request.path == "/home" and response.status_code == 200:
        response = redirect("/home")
        response.set_cookie('prg_guard', '1', max_age=5)  # 5秒保护期
    return response


# =============== 主程序入口 ===============
if __name__ == "__main__":
    # 生成安全密钥，用于会话管理
    app.secret_key = os.urandom(24)


    # 添加安全cookie属性
    @app.after_request
    def add_security_headers(response):
        # 为所有cookie添加安全属性
        for key in request.cookies:
            if key == 'username':
                response.set_cookie(
                    key,
                    request.cookies[key],
                    max_age=3600 * 24,
                    httponly=True,  # 防止XSS攻击
                    secure=True,  # 仅在HTTPS连接中发送
                    samesite='Lax'  # 防止CSRF攻击
                )
        return response


    app.run(debug=True)  # 启动应用，调试模式开启